<template>
  <div class="demo-form-inline">
    <slot v-if="data.slotName" :name="data.slotName" v-bind="{ ...data }" />
    <template v-for="item in config" :key="item.type">
      <component
        ref="allRef"
        style="width: 100%"
        v-if="item.type === data.type"
        v-bind="{
          ...item,
          ...data,
          ...props[item.config],
          onChange: (value) => onChangeValue(value, props[item.config]),
        }"
        v-model="formParam[data.key || data.prop]"
        :is="item.component"
        :placeholder="
          data.p ||
          data.placeholder ||
          `${rulesMessage[data.type]}${data.label}`
        "
        startPlaceholder="开始日期"
        endPlaceholder="结束日期"
        :data="
          typeof data.option === 'string'
            ? optionConfig[data.option]
            : data.option
        "
        :options="
          typeof data.option === 'string'
            ? optionConfig[data.option]
            : data.option
        "
        :props="data?.fieldNames || fieldNames"
        :filter-node-method="
          (value, data) => filterNodeMethod(value, data, data.searchKey)
        "
        :disabled="isDisabled(data.row)"
        clearable
      >
        <template #default v-if="data.type === 'select'">
          <el-option
            v-for="v in typeof data.option === 'string'
              ? optionConfig[data.option]
              : data.option"
            v-bind="v"
            :key="v[data?.fieldNames?.value] || v[fieldNames?.value]"
            :label="v[data?.fieldNames?.label] || v[fieldNames?.label]"
            :value="v[data?.fieldNames?.value] || v[fieldNames?.value]"
          />
        </template>
      </component>
    </template>
  </div>
</template>

<script setup>
import { ref } from "vue";
import { config, propsConfig, fieldNames, rulesMessage } from "./index";

const emit = defineEmits(["changeValue"]);
const props = defineProps({
  // 列表字段，用于效验，新增删除
  keys: { type: String, default: null },
  data: { type: [Array, Object], required: true },
  ...propsConfig,
});

const allRef = ref(null); // 所有组件的ref

// tree搜索
const filterNodeMethod = (value, data, searchKey = "label") =>
  data[searchKey].includes(value);

// 封装禁用状态判断逻辑，使用 “===” 会导致数字和字符串不相等
const isDisabled = (row = null) => {
  const { data, disabledConfig } = props;
  const target = row || data;
  if (typeof data.disabled === "string") {
    // disabledKeys和disabled都存在时，进行对比相同则禁用
    if (target[data.disabledKeys] && disabledConfig[data.disabled]) {
      return !(target[data.disabledKeys] == disabledConfig[data.disabled]);
    }
    // 优先从 disabledConfig 获取外部控制状态
    if (disabledConfig && Object.hasOwn(disabledConfig, data.disabled)) {
      if (typeof disabledConfig[data.disabled] === "boolean") {
        return disabledConfig[data.disabled];
      }
      // 为字符串返回false，防止报错只接受布尔值
      return false;
    }
    // 字段级联动禁用规则：通过 record 的 key 匹配值是否相等并取反
    // 不相等则禁用，相等则打开，根据需求自行调整
    return !(target[data.disabledKeys] == target[data.disabled]);
  }
  // 直接返回静态禁用状态（Boolean），!!用于确保返回布尔值
  return !!data.disabled;
};

// 选择器：获取选中的完整数据项（id, name 等）
const getSelectedOption = (selectData) => {
  const { data, optionConfig } = props;
  const { value, children } = fieldNames;
  const options =
    typeof data.option === "string" ? optionConfig[data.option] : data.option;
  if (!options) return null;
  // 根据选中的 value 获取对应的完整数据项（id, name 等）
  const findOption = (options, val) => {
    for (let option of options) {
      if (option[value] === val) {
        return option;
      }
      if (option[children]) {
        const result = findOption(option[children], val);
        if (result) return result;
      }
    }
    return null;
  };
  return findOption(options, selectData);
};
// 输入框/选择器事件
const onChangeValue = (value, configs = {}) => {
  const { data, formParam } = props;
  /**
   * el不支持当前选中返回所有数据，只返回value（id）
   * 对选择器进行筛选，返回完整数据项（id, name 等）
   */
  const id = Array.isArray(value) ? value[value?.length - 1] : value;
  const option = getSelectedOption(id);
  // 如果 params对象 存在，根据 key:'value' 进行赋值操作
  const params = data?.param || data?.params;
  // 日期类型，返回数组，需要单独处理
  const dateType = ["daterange", "datetimerange", "monthrange"];
  if (params) {
    if (dateType.includes(data.type)) {
      for (const [index, item] of params.entries()) {
        formParam[item] = value?.[index];
      }
      return;
    }
    for (const key in params) {
      formParam[key] = option[params[key]];
    }
    return; // 可选
  }
  // 返回默认参数
  const { onChange } = configs;
  const datas = { id: value, option, type: data.type };
  // 根据字段返回，只做当前处理
  if (configs[datas.key || datas.prop]) {
    return configs[datas.key](datas);
  }
  // 有自定义事件则执行自定义事件
  if (onChange) {
    return onChange(datas);
  }
  // 传递给父组件
  emit("changeValue", datas);
};
</script>

<style lang="scss" scoped>
.demo-form-inline {
  width: 220px !important;
}

// 日期区间选择器溢出问题
:deep(.el-range__icon) {
  padding-left: 10px;
}
:deep(.el-range__close-icon) {
  padding-right: 10px;
}
</style>